﻿using mozhi.smarterp.Finance.AccountsPayables.Repositories;
using mozhi.smarterp.Finance.AccountsPayables.Services;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Payables;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Guids;

namespace mozhi.smarterp.Finance.AccountsPayables.PurchasePayables
{
    public class PurchasePayableAppService : FinanceAppService, IPurchasePayableAppService
    {
        private IPurchasePayableRepository _repository;
        private PurchasePayableManager _manager;
        private IGuidGenerator _guidGenerator;
        private IPurchasePayableReceiptRepository _payableReceiptRepository;

        public PurchasePayableAppService(IPurchasePayableRepository repository, PurchasePayableManager manager , IGuidGenerator guidGenerator, IPurchasePayableReceiptRepository payableReceiptRepository)
        {
            _repository = repository;
            _manager = manager;
            _guidGenerator = guidGenerator;
            _payableReceiptRepository = payableReceiptRepository;
        }

        public async Task<PurchasePayableDto> CreateAsync(PurchasePayableCreateDto input)
        {
            var payable = await _manager.GetAsync(null, input.Date, input.DueDate, input.SupplierId, input.CurrencyId, input.ExchangeRate, input.Type, input.RecognitionModel,
                input.PurchaserDepartmentId, input.PurchaserId, input.PaymentTermId , input.IsCreditNote , input.Comment);

            input.Items = input.Items ?? new List<PurchasePayableItemCreateDto>();

            var payableItems = new List<PurchasePayableItem>();

            var payableReceipts = new List<PurchasePayableReceipt>();

            foreach (var item in input.Items)
            {
                var payableItem = await _manager.GetItemAsync(null, item.ProductId, item.ExpenseItemId, item.Price, item.TaxRateId, item.BasicQuantity, item.AmountFr, item.ExpenseBurdenDepartmentId, item.Remark);

                payableItems.Add(payableItem);

                if (input.SourceId.HasValue && item.SourceItemId.HasValue)
                    payableReceipts.Add(new PurchasePayableReceipt(_guidGenerator.Create(), payable.Id, payableItem.Id, input.SourceId.Value, item.SourceItemId.Value));
            }

            payable.SetItems(payableItems);

            payable = await _repository.InsertAsync(payable);

            await _payableReceiptRepository.InsertManyAsync(payableReceipts);

            var result = ObjectMapper.Map<PurchasePayable , PurchasePayableDto>(payable);

            return result;
        }

        public async Task DeleteAsync(Guid id)
        {
            await _manager.DeleteAsync(id);
        }

        public async Task<PurchasePayableDto> GetAsync(Guid id)
        {
            var payable = await _repository.GetAsync(id);

            var result = ObjectMapper.Map<PurchasePayable, PurchasePayableDto>(payable);

            return result;
        }

        public async Task<PagedResultDto<PurchasePayableDto>> GetListAsync(PurchasePayablePagedResultRequestDto filter)
        {
            var payables = await _repository.GetPagedListAsync(filter.Keyword , filter.Number , filter.SupplierId , filter.CurrencyId , filter.SkipCount , filter.MaxResultCount , filter.Sorting);

            var count = await _repository.GetCountAsync(filter.Keyword, filter.Number, filter.SupplierId, filter.CurrencyId, null);

            var items = ObjectMapper.Map<List<PurchasePayable>, List<PurchasePayableDto>>(payables);

            return new PagedResultDto<PurchasePayableDto>()
            {
                Items = items,
                TotalCount = count
            };
        }

        public async Task<PurchasePayableDto> UpdateAsync(PurchasePayableUpdateDto input)
        {
            var payable = await _manager.GetAsync(input.Id, input.Date, input.DueDate, input.SupplierId, input.CurrencyId, input.ExchangeRate, input.Type, input.RecognitionModel,
               input.PurchaserDepartmentId, input.PurchaserId, input.PaymentTermId, false, input.Comment);

            input.Items = input.Items ?? new List<PurchasePayableItemUpdateDto>();

            var payableItems = new List<PurchasePayableItem>();

            foreach (var item in input.Items)
            {
                var payableItem = await _manager.GetItemAsync(item.Id, item.ProductId, item.ExpenseItemId, item.Price, item.TaxRateId, item.BasicQuantity, item.AmountFr, item.ExpenseBurdenDepartmentId, item.Remark);

                payableItems.Add(payableItem);
            }

            payable.SetItems(payableItems);

            payable = await _repository.InsertAsync(payable);

            var result = ObjectMapper.Map<PurchasePayable, PurchasePayableDto>(payable);

            return result;
        }

        public async Task UpdateStatusAsync(Guid id , DocumentStatusType status)
        {
             await _manager.UpdateStatusAsync(id, status);
        }

        public async Task<Guid> PushPaymentAsync(Guid id)
        {
            return await _manager.PushPaymentAsync(id);
        }
    }
}
